/***************************************************************************
 *   Copyright (C) 2005 by xihe   *
 *   xihels@163.com                                                        *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/

#ifndef PACKET_H
#define PACKET_H
#include <stdint.h>
#include <netinet/in.h>

#include <string>
#include <vector>
#include <stdexcept>
using std::string;
using std::vector;
using std::runtime_error;

#include "QQ.h"
// 消息发送次数
#define SEND_IM_COUNT	2
// 一般发送次数
#define SEND_COUNT	4


inline int writeBufB(uint8_t* buf, uint8_t s)
{
    *buf = s;
    return sizeof(s);
}

inline int writeBufB(uint8_t* buf, uint8_t s, int count)
{
    memset(buf, s, count);
    return count;
}

inline int writeBufW(uint8_t* buf, uint16_t s)
{
    *reinterpret_cast<uint16_t*>(buf) = htons(s);
    return sizeof (s);
}

inline int writeBufDw(uint8_t* buf, uint32_t s)
{
    *reinterpret_cast<uint32_t*>(buf) = htonl(s);
    return sizeof (s);
}

inline int writeBufData(uint8_t* buf, const uint8_t* s, int len)
{
    memcpy(buf, s, len);
    return len;
}

inline int readBufB(uint8_t& d, const uint8_t* buf) 
{
    d = *buf;
    return sizeof (d);
}

inline int readBufW(uint16_t& d, const uint8_t* buf)
{
    d = ntohs(*reinterpret_cast<const uint16_t*>(buf));
    return sizeof (d);
}

inline int readBufDw(uint32_t& d, const uint8_t* buf)
{
    d = ntohl(*reinterpret_cast<const uint32_t*>(buf));
    return sizeof (d);
}



/**
 * QQ所有包对象的基类
 * 包头字节 0x00
 * 源标志 0x01~0x02
 * 包命令 0x03~0x04
 * 包序号 0x05~0x06
 */



class Packet {
    protected:
	Packet(uint16_t _source,
		uint16_t _command,
		uint16_t _sequence,
		uint8_t _header) :
	    source(_source),
	    command(_command),
	    sequence(_sequence),
	    header(_header)
	{}
	Packet(const uint8_t* buf, 
		int len) :
	    header(*buf),
	    source(ntohs(*reinterpret_cast<const uint16_t*>(buf + 1))),
	    command(ntohs(*reinterpret_cast<const uint16_t*>(buf + 3))),
	    sequence(ntohs(*reinterpret_cast<const uint16_t*>(buf + 5)))
	{}


	virtual ~Packet() = 0;
    public:

	uint16_t getSource() const	    { return source; }
	uint16_t getCommand() const	    { return command; }
	uint16_t getSequence() const    { return sequence; }
	void     setSequence(uint16_t _sequence) { sequence = _sequence; }
	uint8_t  getHeader() const	    { return header; }

	static uint8_t getHeader(const uint8_t* buf) { return *buf; }

	static uint16_t getCommand(const uint8_t* buf)
	{
	    return ntohs(*reinterpret_cast<const uint16_t*>(buf + 3));
	}

	static uint16_t getSequence(const uint8_t* buf)
	{
	    return ntohs(*reinterpret_cast<const uint16_t*>(buf + 5));
	}


    protected:
	uint16_t source;	// 源标志 0x01~0x02
	uint16_t command;	// 包命令 0x03~0x04
	uint16_t sequence;	// 包序号 0x05~0x06
	uint8_t  header;	// 包头字节 0x00
    private:
	Packet(const Packet& rhs);
	Packet& operator = (const Packet& rhs);
};
inline Packet::~Packet(){}



/**
 * 所有输出包基类
 */
class QQClient;
class OutPacket : public Packet {
    protected:
	OutPacket(QQClient& cl,
		uint16_t _command,
		int	 _sendCount = 1);

	OutPacket(const QQClient& cl, 
		const uint8_t* buf);

    public:

	time_t  sendTime()  const	{ return sendTime_; }
	void	sendTime(time_t _time)	{ sendTime_ = _time; }
	
	int	stepSendCount()		{ return sendCount_--; }

	int	putHead(uint8_t* buf) const;
	virtual int putBody(uint8_t* buf) const = 0;
    protected:
	const   QQClient& client; // QQ客户
	time_t  sendTime_;	// 发送时间
	int	sendCount_;	// 还要再发送次数
};

/**
 * 所有输入包基类
 */


class InPacket : public Packet {
    protected:
	InPacket(const uint8_t* buf,
		int		len,
		bool		_retell = false) :
	    Packet(buf, len),
	    retell_(_retell)
	{}

    public:
	virtual void process(QQClient& client) = 0;

	bool retell()	const { return retell_; }
    private:
	bool		retell_;// 如为真，需要查找一下重发队列,
				// 以清除对应的输出包.

};


/**
 * 同步包
 */
class ReplyPacket : public OutPacket {
    public:
	ReplyPacket(const QQClient& cl, const uint8_t* buf);
	int putBody(uint8_t* buf) const;
    private:
	uint8_t ackBody[16];
};

/**
 * 所有未知的输入包
 */
class UnknowPacket : public InPacket {
    protected:
	UnknowPacket(const uint8_t* buf, int len); 
    public:
	const string& getUnknow() const { return unknow; }
	static InPacket* create(const uint8_t* buf, int len)
	{
	    return new UnknowPacket(buf, len);
	}
	void process(QQClient& client);
    private:
	string unknow;	    // 未知数据
};

#endif //PACKET_H

